package com.icebartech.core.utils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;  
import javax.crypto.Cipher;  
import javax.crypto.NoSuchPaddingException;  
import javax.crypto.spec.IvParameterSpec;  
import javax.crypto.spec.SecretKeySpec;  
import java.security.Key;  
import java.security.NoSuchAlgorithmException;  
import java.security.NoSuchProviderException;  
import java.security.Security;  
/**  
 * Created by wind on 2016/12/24.  
 */  
/**  
 *  
 * @author ngh  
 * AES128 算法  
 *  
 * CBC 模式  
 *  
 * PKCS7Padding 填充模式  
 *  
 * CBC模式需要添加一个参数iv--对称解密算法初始向量 iv  
 *  
 * 介于java 不支持PKCS7Padding，只支持PKCS5Padding 但是PKCS7Padding 和 PKCS5Padding 没有什么区别  
 * 要实现在java端用PKCS7Padding填充，需要用到bouncycastle组件来实现  
 */  
public class Pkcs7Encoder {  
    // 算法名称  
    static  final String KEY_ALGORITHM = "AES";  
    // 加解密算法/模式/填充方式  
    static  final String algorithmStr = "AES/CBC/PKCS7Padding";  
    private static Key key;  
    private static Cipher cipher;  
    // boolean isInited = false;
    //默认对称解密算法初始向量 iv  
    static byte[] iv = { 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38 };  
    public static void init(byte[] keyBytes) {  
        // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要  
        int base = 16;  
        if (keyBytes.length % base != 0) {  
            int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);  
            byte[] temp = new byte[groups * base];  
            Arrays.fill(temp, (byte) 0);  
            System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);  
            keyBytes = temp;  
        }  
        // 初始化  
        Security.addProvider(new BouncyCastleProvider());  
        // 转化成JAVA的密钥格式  
        key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);  
        try {  
            // 初始化cipher  
            cipher = Cipher.getInstance(algorithmStr, "BC");  
        } catch (NoSuchAlgorithmException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        } catch (NoSuchPaddingException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        } catch (NoSuchProviderException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  
    /**  
     * 加密方法  
     *      --使用默认iv时  
     * @param content  
     *            要加密的字符串  
     * @param keyBytes  
     *            加密密钥  
     * @return  
     */  
    public static byte[] encrypt(byte[] content, byte[] keyBytes) {  
        byte[] encryptedText =  encryptOfDiyIV(content,keyBytes,iv);  
        return encryptedText;  
    }  
    /**  
     * 解密方法  
     *      --使用默认iv时  
     * @param encryptedData  
     *            要解密的字符串  
     * @param keyBytes  
     *            解密密钥  
     * @return  
     */  
    public static byte[] decrypt(byte[] encryptedData, byte[] keyBytes) throws Exception {  
        byte[] encryptedText = decryptOfDiyIV(encryptedData,keyBytes,iv);  
        return encryptedText;  
    }  
    /**  
     * 加密方法  
     *      ---自定义对称解密算法初始向量 iv  
     * @param content  
     *              要加密的字符串  
     * @param keyBytes  
     *              加密密钥  
     * @param ivs  
     *         自定义对称解密算法初始向量 iv  
     * @return 加密的结果  
     */  
    public static byte[] encryptOfDiyIV(byte[] content, byte[] keyBytes, byte[] ivs) {
        byte[] encryptedText = null;  
        init(keyBytes);  
        try {
            System.out.println("IV：" + new String(ivs, "UTF-8"));
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivs));
            encryptedText = cipher.doFinal(content);  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        return encryptedText;  
    }  
    /**  
     * 解密方法  
     *  
     * @param encryptedData  
     *            要解密的字符串  
     * @param keyBytes  
     *            解密密钥  
     * @param ivs  
     *         自定义对称解密算法初始向量 iv  
     * @return  
     */  
    public static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes,byte[] ivs) throws Exception {  
        byte[] encryptedText = null;
        init(keyBytes);
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));  
        encryptedText = cipher.doFinal(encryptedData);  
        return encryptedText;  
    }  
}  